<script lang="ts" setup>
import { throttle } from '@/lib/util'
import { computed, onMounted, onUnmounted, ref, toRefs } from 'vue'
const props = defineProps<{
  left: number
  contentWidth: number
  wrapWidth: number
}>()
const emit = defineEmits(['update:left'])
const { left, contentWidth, wrapWidth } = toRefs(props)
const scrollWidth = ref(0)
const scale = computed(() => wrapWidth.value / contentWidth.value)
const maxMove = computed(() => scrollWidth.value - sliderWith.value)
const sliderWith = computed(() => scrollWidth.value * scale.value)
const sliderLeft = computed({
  // getter
  get() {
    return left.value * scale.value
  },
  // setter
  set(newValue: number) {
    let move = newValue
    if (move < 0) move = 0
    if (move > maxMove.value) move = maxMove.value
    emit('update:left', move / scale.value)
  }
})
const scrollRef = ref<HTMLDivElement | null>(null)
const sliderRef = ref<HTMLDivElement | null>(null)

let startPageX = 0 // 拖拽开始X坐标
let startScrollLeft = 0 // 拖拽开始时的滚动条偏移

const clickScroll = (e: MouseEvent) => {
  sliderLeft.value = e.offsetX
}

const getScrollWidth = throttle(
  50,
  () => {
    scrollWidth.value = scrollRef.value?.clientWidth || 0
  },
  true
)

function pauseEvent(e: MouseEvent) {
  if (e.stopPropagation) e.stopPropagation()
  if (e.preventDefault) e.preventDefault()
  e.cancelBubble = true
  e.returnValue = false
  return false
}

const onMoveStart = (e: MouseEvent) => {
  startPageX = e.pageX
  startScrollLeft = sliderLeft.value
  window.addEventListener('mousemove', onMoving)
  window.addEventListener('mouseup', onMoveEnd)
  pauseEvent(e)
}

const onMoving = (e: MouseEvent) => {
  const moveX = e.pageX - startPageX
  sliderLeft.value = startScrollLeft + moveX
  pauseEvent(e)
}

const onMoveEnd = (e: MouseEvent) => {
  startPageX = 0
  startScrollLeft = 0
  window.removeEventListener('mousemove', onMoving)
  window.removeEventListener('mouseup', onMoveEnd)
  pauseEvent(e)
}

const onScroll = (e: WheelEvent) => {
  const isUp = e.deltaY < 0
  const step = scrollWidth.value / 20
  const move = isUp ? -step : step
  smoothMove(move)
}

const smoothMove = (moveTotal: number) => {
  const step = moveTotal > 0 ? 3 : -3
  let curMove = 0
  const moveFun = () => {
    sliderLeft.value = sliderLeft.value + step
    curMove += step
    if (Math.abs(curMove) < Math.abs(moveTotal)) {
      setTimeout(moveFun, 10)
    }
  }

  moveFun()
}

onMounted(() => {
  getScrollWidth()
  window.addEventListener('resize', getScrollWidth)
})

onUnmounted(() => {
  window.removeEventListener('resize', getScrollWidth)
})
</script>
<template>
  <div
    class="scroll-bar"
    ref="scrollRef"
    @mousedown.left.self="clickScroll"
    @mousewheel.prevent="onScroll"
  >
    <div
      class="scroll-slider"
      ref="sliderRef"
      @mousedown.left="onMoveStart"
      :style="{ left: sliderLeft + 'px', width: sliderWith + 'px' }"
    ></div>
  </div>
</template>
<style scoped lang="stylus">
.scroll-bar
  width 100%
  height 8px
  user-select none
  .scroll-slider
    position relative
    z-index 9999
    background-color #646464
    border-radius 14px
    height 100%
    transition background-color .2s ease
  .scroll-slider:hover {
    background-color #868686
    cursor pointer
  }
</style>
